package com.google.code.jholidays.core;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

import com.google.code.jholidays.events.IEvent;
import com.google.code.jholidays.events.IFactory;
import com.google.code.jholidays.moc.AlphaEvent;
import com.google.code.jholidays.moc.AlphaFactoryMoc;
import com.google.code.jholidays.moc.FactoryMoc;
import com.google.code.jholidays.moc.NumberEvent;
import com.google.code.jholidays.moc.NumberFactoryMoc;

public class CompositeFactoryTest {

    @Test
    public void testAdd() {
	CompositeFactory factory = new CompositeFactory();
	IFactory moc = new FactoryMoc();

	assertTrue(factory.add(moc));
	assertFalse(factory.add(null));
    }

    @Test
    public void testContainsOne() {
	CompositeFactory factory = new CompositeFactory();
	IFactory moc = new FactoryMoc();

	assertTrue(factory.add(moc));
	assertTrue(factory.contains(moc));
    }

    @Test
    public void testAddMany() {
	CompositeFactory factory = new CompositeFactory();
	IFactory moc = new FactoryMoc();
	IFactory moc2 = new NumberFactoryMoc();
	IFactory moc3 = new AlphaFactoryMoc();

	assertTrue(factory.add(moc));
	assertTrue(factory.add(moc2));
	assertTrue(factory.add(moc3));
    }

    @Test
    public void testContainsMany() {
	CompositeFactory factory = new CompositeFactory();
	IFactory moc = new FactoryMoc();
	IFactory moc2 = new NumberFactoryMoc();
	IFactory moc3 = new AlphaFactoryMoc();

	assertTrue(factory.add(moc));
	assertTrue(factory.add(moc2));
	assertTrue(factory.add(moc3));

	assertTrue(factory.contains(moc));
	assertTrue(factory.contains(moc2));
	assertTrue(factory.contains(moc3));
    }

    @Test
    public void testRemove() {
	CompositeFactory factory = new CompositeFactory();
	IFactory moc = new FactoryMoc();
	IFactory moc2 = new NumberFactoryMoc();
	IFactory moc3 = new AlphaFactoryMoc();

	assertTrue(factory.add(moc));
	assertTrue(factory.add(moc2));
	assertTrue(factory.add(moc3));

	assertTrue(factory.contains(moc));
	assertTrue(factory.contains(moc2));
	assertTrue(factory.contains(moc3));

	assertEquals(factory.remove(moc), moc);
	assertEquals(factory.remove(moc2), moc2);
	assertEquals(factory.remove(moc3), moc3);

	assertFalse(factory.contains(moc));
	assertFalse(factory.contains(moc2));
	assertFalse(factory.contains(moc3));
    }

    @Test
    public void testMatches() {

	// also tests getFactory()

	String knownExpression = "1234567890"; // string of numbers;

	EventDescriptor descriptor = new EventDescriptor(1);
	descriptor.setExpression(knownExpression);

	// test factory moc first
	NumberFactoryMoc moc2 = new NumberFactoryMoc();
	assertTrue(moc2.matches(descriptor));

	// test composite factory
	CompositeFactory factory = new CompositeFactory();
	IFactory moc = new FactoryMoc();
	IFactory moc3 = new AlphaFactoryMoc();

	assertTrue(factory.add(moc));
	assertTrue(factory.add(moc2));
	assertTrue(factory.add(moc3));

	assertTrue(factory.matches(descriptor));

	IFactory f = factory.getFactory(descriptor);
	assertNotNull(f);
	assertSame(f, moc2);

	// change expression
	String newExpression = "abcdefg";
	descriptor.setExpression(newExpression);

	assertTrue(factory.matches(descriptor));

	f = factory.getFactory(descriptor);
	assertNotNull(f);
	assertSame(f, moc3);
    }

    @Test
    public void testCreateEvent() {
	final String numberExpression = "1234567890";
	final String alphaExpression = "abcdefghujk";

	EventDescriptor numberDescriptor = new EventDescriptor(1);
	numberDescriptor.setExpression(numberExpression);

	EventDescriptor alphaDescriptor = new EventDescriptor(2);
	alphaDescriptor.setExpression(alphaExpression);

	CompositeFactory factory = new CompositeFactory();
	IFactory moc = new FactoryMoc();
	IFactory numberFactMoc = new NumberFactoryMoc();
	IFactory alphaFactMoc = new AlphaFactoryMoc();

	assertTrue(factory.add(moc));
	assertTrue(factory.add(numberFactMoc));
	assertTrue(factory.add(alphaFactMoc));

	IEvent numberEvent = factory.createEvent(numberDescriptor, null);
	assertNotNull(numberEvent);
	assertTrue(numberEvent instanceof NumberEvent);
	assertEquals(1, numberEvent.getID());

	IEvent alphaEvent = factory.createEvent(alphaDescriptor, null);
	assertNotNull(alphaEvent);
	assertTrue(alphaEvent instanceof AlphaEvent);
	assertEquals(2, alphaEvent.getID());

	// remove factories
	assertSame(factory.remove(numberFactMoc), numberFactMoc);
	numberEvent = factory.createEvent(numberDescriptor, null);
	assertNull(numberEvent);

	assertSame(factory.remove(alphaFactMoc), alphaFactMoc);
	alphaEvent = factory.createEvent(alphaDescriptor, null);
	assertNull(alphaEvent);
    }
}
